package com.bw.lib_avcore;

import android.graphics.ImageFormat;
import android.hardware.Camera;
import android.media.MediaCodecInfo;
import android.util.Log;
import android.view.SurfaceHolder;

import com.bw.lib_avcore.utisl.RotateYUVUtils;
import com.bw.lib_avcore.utisl.Yuv420Util;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.LinkedBlockingDeque;

/**
 * @author ytx
 * @date 2025-10-23 10:47
 * @description 摄像头采集
 */
public class VideoHelper {
    public static final String TAG = "VideoHelper";
    private Camera mCamera; //相机
    private Camera.Size mPreviewSize;//预览尺寸

    private Config mConfig; //配置

    private int colorFormat;//颜色格式

    public void setColorFormat(int colorFormat) {
        this.colorFormat = colorFormat;
    }

    private LinkedBlockingDeque<PixelData> mQueue = new LinkedBlockingDeque<>(); //队列 解决背压问题 生产者消费者模式

    private Thread workThread; //工作线程
    private boolean loop;//是否轮询

    //单例
    private VideoHelper(Config config){
        this.mConfig = config;
    }
    private volatile static VideoHelper instance;
    public static VideoHelper getInstance(Config config){
        if(instance == null){
            synchronized (VideoHelper.class){
                if(instance == null){
                    instance = new VideoHelper(config);
                }
            }
        }
        return instance;
    }


    /**
     * 初始化相机-SurfaceView
     */
    public Params initCamera(SurfaceHolder surfaceHolder){
        release();
        openCamera();
        setCameraParams();
        mCamera.setDisplayOrientation(270);
        //设置预览画面
        try {
            mCamera.setPreviewDisplay(surfaceHolder);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        mCamera.setPreviewCallbackWithBuffer(mPreviewCallback); //设置预览回调数据
        mCamera.addCallbackBuffer(new byte[calculateFrameSize()]); //设置预览数据缓存区
        mCamera.startPreview(); //开启预览



        //取出线程。不断队列中取出数据
        initWorkThread();
        loop = true;
        workThread.start();

        return new Params(mPreviewSize.width,mPreviewSize.height);



    }

    private void initWorkThread(){
        workThread = new Thread(){
            byte[] dstByte = new byte[calculateFrameSize()]; //转换后
            @Override
            public void run() {
                super.run();
                while (loop && !Thread.currentThread().isInterrupted()){
                    try {
                        //取出数据
                        PixelData pixelData = mQueue.take();
                        // 处理:NV21--->I420
                        if (colorFormat == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420SemiPlanar) {
                            Yuv420Util.Nv21ToYuv420SP(pixelData.data, dstByte, mPreviewSize.width,
                                    mPreviewSize.height);
                        } else if (colorFormat == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Planar) {
                            Yuv420Util.Nv21ToI420(pixelData.data, dstByte, mPreviewSize.width,
                                    mPreviewSize.height);
                        } else if (colorFormat == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420Flexible) {
                            // Yuv420_888
                        } else if (colorFormat == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedPlanar) {
                            // Yuv420packedPlannar 和 yuv420sp很像
                            // 区别在于 加入 width = 4的话 y1,y2,y3 ,y4公用 u1v1
                            // 而 yuv420dp 则是 y1y2y5y6 共用 u1v1
                            //这样处理的话颜色核能会有些失真。
                            Yuv420Util.Nv21ToYuv420SP(pixelData.data, dstByte, mPreviewSize.width,
                                    mPreviewSize.height);
                        } else if (colorFormat == MediaCodecInfo.CodecCapabilities.COLOR_FormatYUV420PackedSemiPlanar) {
                        } else {
                            System.arraycopy(pixelData.data, 0, dstByte, 0, pixelData.data.length);
                        }

                        //接口回调
                        if (mCallback != null){
                            mCallback.onReceive(dstByte,colorFormat);
                        }





                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        };

    }




    /**
     * 计算一帧数据大小
     * @return
     */
    private int calculateFrameSize(){
        return mPreviewSize.width * mPreviewSize.height * ImageFormat.getBitsPerPixel(ImageFormat.NV21) / 8;
    }
    /**
     * 预览数据回调
     */
    public Camera.PreviewCallback mPreviewCallback = new Camera.PreviewCallback() {
        @Override
        public void onPreviewFrame(byte[] data, Camera camera) {
            Log.d(TAG, "摄像头采集的原始数据: "+data);
            if (data != null){
                data = RotateYUVUtils.rotateYUVDegree90(data, mPreviewSize.width, mPreviewSize.height);
                //放入队列
                try {
                    mQueue.put(new PixelData(ImageFormat.NV21,data));
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            // 关键！归还缓冲区，否则下次不会回调
            camera.addCallbackBuffer(new byte[calculateFrameSize()]);
        }
    };

    /**
     * 设置相机参数
     */
    public void setCameraParams(){
        Camera.Parameters parameters = mCamera.getParameters(); //获得参数

        //大小
        List<Camera.Size> supportedPreviewSizes = parameters.getSupportedPreviewSizes();//获得支持的预览尺寸
        for (Camera.Size size : supportedPreviewSizes){
            if (size.width >= mConfig.minWidth && size.width <= mConfig.maxWidth){//在指定范围内
                mPreviewSize = size;
                break;
            }
        }
        parameters.setPreviewSize(mPreviewSize.width, mPreviewSize.height);

        //帧率
//        int[] fpsRange = {mConfig.fps * 1000,mConfig.fps * 1000};
//        List<int[]> supportedPreviewFpsRange = parameters.getSupportedPreviewFpsRange();//获得支持帧率
//        for (int[] range : supportedPreviewFpsRange){
//            if (mConfig.fps >=range[Camera.Parameters.PREVIEW_FPS_MIN_INDEX] && mConfig.fps <= range[Camera.Parameters.PREVIEW_FPS_MAX_INDEX]){
//                fpsRange = range;
//                break;
//            }
//        }
//        parameters.setPreviewFpsRange(fpsRange[Camera.Parameters.PREVIEW_FPS_MIN_INDEX],Camera.Parameters.PREVIEW_FPS_MAX_INDEX);

        //图片格式
        parameters.setPreviewFormat(ImageFormat.NV21);
        //自动聚焦
        parameters.setFocusMode(Camera.Parameters.FOCUS_MODE_AUTO);


        mCamera.setParameters(parameters);

    }


    /**
     * 释放相机
     */
    public void release(){
        if (mCamera != null){
            mCamera.setPreviewCallback(null);
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
    }

    /**
     * 打开相机
     */

    public void openCamera(){
        if (mCamera == null){
            try {
                mCamera = Camera.open(1); //0 后置 1：前置
            } catch (Exception e) {
                Log.d(TAG, "打开相机失败: "+e.getMessage());
                e.printStackTrace();
            }

        }
    }


    /**
     * 像素数据
     */
    public static class PixelData {
        public final int format;//格式
        public final byte[] data; //数据

        public PixelData(int format, byte[] data) {
            this.format = format;
            this.data = data;
        }

    }

    //数据接口回调
    private Callback mCallback;

    interface Callback {
        void onReceive(byte[] data, int colorFormat);
    }

    public void setCallback(Callback callback) {
        this.mCallback = callback;
    }


    public class Params{
        public int width ;
        public int height;
        public Params(int width, int height){
            this.width = width;
            this.height = height;
        }
    }


}
